#!/bin/bash

# 连通性自检脚本
# 用于验证服务器、数据库、域名和API的连通性
# 使用方法: chmod +x connectivity-test.sh && ./connectivity-test.sh

echo "🔍 开始连通性自检..."
echo "测试时间: $(date)"
echo "========================================"

# 配置变量
SERVER_IP="47.237.10.129"
DB_HOST="rm-t4n2um727ltmubz.mysql.singapore.rds.aliyuncs.com"
DB_PORT="3306"
DB_USER="cmb_admin"
DB_PASS="132Singer45#\$"
DB_NAME="cumrbull"

API_DOMAIN="api.cumrbull.com.sg"
ADMIN_DOMAIN="admin.cumrbull.com.sg"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0

# 日志函数
log_test() {
    TOTAL_TESTS=$((TOTAL_TESTS + 1))
    echo -e "${BLUE}[TEST $TOTAL_TESTS]${NC} $1"
}

log_pass() {
    PASSED_TESTS=$((PASSED_TESTS + 1))
    echo -e "${GREEN}[PASS]${NC} $1"
}

log_fail() {
    FAILED_TESTS=$((FAILED_TESTS + 1))
    echo -e "${RED}[FAIL]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

# 1. DNS解析测试
test_dns_resolution() {
    echo "\n🌐 DNS解析测试"
    echo "----------------------------------------"
    
    # 测试API域名
    log_test "解析 $API_DOMAIN"
    if nslookup $API_DOMAIN | grep -q "$SERVER_IP"; then
        log_pass "$API_DOMAIN 正确解析到 $SERVER_IP"
    else
        log_fail "$API_DOMAIN 解析失败或指向错误IP"
        nslookup $API_DOMAIN
    fi
    
    # 测试管理后台域名
    log_test "解析 $ADMIN_DOMAIN"
    if nslookup $ADMIN_DOMAIN | grep -q "$SERVER_IP"; then
        log_pass "$ADMIN_DOMAIN 正确解析到 $SERVER_IP"
    else
        log_fail "$ADMIN_DOMAIN 解析失败或指向错误IP"
        nslookup $ADMIN_DOMAIN
    fi
    
    # 使用dig进行详细测试
    log_test "使用dig验证DNS记录"
    if command -v dig &> /dev/null; then
        echo "API域名详细信息:"
        dig +short $API_DOMAIN
        echo "管理后台域名详细信息:"
        dig +short $ADMIN_DOMAIN
        log_pass "dig命令执行成功"
    else
        log_warn "dig命令不可用，跳过详细DNS测试"
    fi
}

# 2. 端口连通性测试
test_port_connectivity() {
    echo "\n🔌 端口连通性测试"
    echo "----------------------------------------"
    
    # 测试常用端口
    ports=("22:SSH" "80:HTTP" "443:HTTPS" "3000:Node.js" "3306:MySQL")
    
    for port_info in "${ports[@]}"; do
        port=$(echo $port_info | cut -d: -f1)
        service=$(echo $port_info | cut -d: -f2)
        
        log_test "测试端口 $port ($service)"
        if timeout 10 bash -c "</dev/tcp/$SERVER_IP/$port" 2>/dev/null; then
            log_pass "端口 $port ($service) 连接成功"
        else
            # 使用nc作为备选方案
            if command -v nc &> /dev/null; then
                if nc -z -w5 $SERVER_IP $port 2>/dev/null; then
                    log_pass "端口 $port ($service) 连接成功 (nc)"
                else
                    log_fail "端口 $port ($service) 连接失败"
                fi
            else
                log_fail "端口 $port ($service) 连接失败"
            fi
        fi
    done
}

# 3. SSL证书测试
test_ssl_certificates() {
    echo "\n🔐 SSL证书测试"
    echo "----------------------------------------"
    
    # 测试API域名SSL
    log_test "检查 $API_DOMAIN SSL证书"
    if timeout 10 openssl s_client -connect $API_DOMAIN:443 -servername $API_DOMAIN </dev/null 2>/dev/null | openssl x509 -noout -dates 2>/dev/null; then
        log_pass "$API_DOMAIN SSL证书有效"
        # 显示证书详细信息
        echo "证书有效期:"
        timeout 10 openssl s_client -connect $API_DOMAIN:443 -servername $API_DOMAIN </dev/null 2>/dev/null | openssl x509 -noout -dates 2>/dev/null
    else
        log_fail "$API_DOMAIN SSL证书检查失败"
    fi
    
    # 测试管理后台域名SSL
    log_test "检查 $ADMIN_DOMAIN SSL证书"
    if timeout 10 openssl s_client -connect $ADMIN_DOMAIN:443 -servername $ADMIN_DOMAIN </dev/null 2>/dev/null | openssl x509 -noout -dates 2>/dev/null; then
        log_pass "$ADMIN_DOMAIN SSL证书有效"
        echo "证书有效期:"
        timeout 10 openssl s_client -connect $ADMIN_DOMAIN:443 -servername $ADMIN_DOMAIN </dev/null 2>/dev/null | openssl x509 -noout -dates 2>/dev/null
    else
        log_fail "$ADMIN_DOMAIN SSL证书检查失败"
    fi
}

# 4. HTTP/HTTPS响应测试
test_http_responses() {
    echo "\n🌐 HTTP/HTTPS响应测试"
    echo "----------------------------------------"
    
    # 测试HTTP重定向
    log_test "测试HTTP到HTTPS重定向"
    http_response=$(curl -s -o /dev/null -w "%{http_code}" -L http://$API_DOMAIN/ 2>/dev/null)
    if [[ "$http_response" == "200" || "$http_response" == "301" || "$http_response" == "302" ]]; then
        log_pass "HTTP重定向正常 (状态码: $http_response)"
    else
        log_fail "HTTP重定向异常 (状态码: $http_response)"
    fi
    
    # 测试HTTPS根路径
    log_test "测试HTTPS根路径访问"
    https_response=$(curl -s -o /dev/null -w "%{http_code}" -k https://$API_DOMAIN/ 2>/dev/null)
    if [[ "$https_response" == "200" ]]; then
        log_pass "HTTPS根路径访问正常 (状态码: $https_response)"
    else
        log_fail "HTTPS根路径访问异常 (状态码: $https_response)"
        log_info "响应内容预览:"
        curl -s -k https://$API_DOMAIN/ 2>/dev/null | head -5
    fi
}

# 5. API健康检查测试
test_api_health() {
    echo "\n🏥 API健康检查测试"
    echo "----------------------------------------"
    
    # 测试API健康检查
    log_test "测试API健康检查端点"
    api_health=$(curl -s -o /dev/null -w "%{http_code}" -k https://$API_DOMAIN/health 2>/dev/null)
    if [[ "$api_health" == "200" ]]; then
        log_pass "API健康检查正常 (状态码: $api_health)"
        echo "健康检查响应:"
        curl -s -k https://$API_DOMAIN/health 2>/dev/null | head -3
    else
        log_fail "API健康检查失败 (状态码: $api_health)"
        log_info "尝试获取错误信息:"
        curl -s -k https://$API_DOMAIN/health 2>/dev/null | head -5
    fi
    
    # 测试管理后台API健康检查
    log_test "测试管理后台API健康检查"
    admin_health=$(curl -s -o /dev/null -w "%{http_code}" -k https://$ADMIN_DOMAIN/api/health 2>/dev/null)
    if [[ "$admin_health" == "200" ]]; then
        log_pass "管理后台API健康检查正常 (状态码: $admin_health)"
        echo "健康检查响应:"
        curl -s -k https://$ADMIN_DOMAIN/api/health 2>/dev/null | head -3
    else
        log_fail "管理后台API健康检查失败 (状态码: $admin_health)"
        log_info "尝试获取错误信息:"
        curl -s -k https://$ADMIN_DOMAIN/api/health 2>/dev/null | head -5
    fi
    
    # 测试API信息端点
    log_test "测试API信息端点"
    api_info=$(curl -s -o /dev/null -w "%{http_code}" -k https://$API_DOMAIN/api 2>/dev/null)
    if [[ "$api_info" == "200" ]]; then
        log_pass "API信息端点正常 (状态码: $api_info)"
        echo "API信息:"
        curl -s -k https://$API_DOMAIN/api 2>/dev/null | head -5
    else
        log_warn "API信息端点异常 (状态码: $api_info)"
    fi
}

# 6. 数据库连接测试
test_database_connection() {
    echo "\n🗄️ 数据库连接测试"
    echo "----------------------------------------"
    
    # 检查MySQL客户端
    log_test "检查MySQL客户端可用性"
    if command -v mysql &> /dev/null; then
        log_pass "MySQL客户端已安装"
        
        # 测试数据库连接
        log_test "测试数据库连接"
        if timeout 15 mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "SELECT 1;" $DB_NAME 2>/dev/null; then
            log_pass "数据库连接成功"
            
            # 获取数据库信息
            log_info "数据库版本信息:"
            timeout 10 mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "SELECT VERSION();" $DB_NAME 2>/dev/null
            
            log_info "数据库表统计:"
            timeout 10 mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "SELECT COUNT(*) as table_count FROM information_schema.tables WHERE table_schema='$DB_NAME';" $DB_NAME 2>/dev/null
        else
            log_fail "数据库连接失败"
            log_info "可能的原因:"
            echo "  1. 数据库服务器未启动"
            echo "  2. 网络连接问题"
            echo "  3. 认证信息错误"
            echo "  4. 防火墙阻止连接"
        fi
    else
        log_warn "MySQL客户端未安装，跳过数据库连接测试"
        log_info "安装MySQL客户端: brew install mysql (macOS) 或 apt-get install mysql-client (Ubuntu)"
    fi
    
    # 使用Node.js测试数据库连接（如果可能）
    log_test "使用Node.js测试数据库连接"
    if command -v node &> /dev/null && [ -f "package.json" ]; then
        cat > test-db-connection.js << EOF
const mysql = require('mysql2/promise');

(async () => {
  try {
    const connection = await mysql.createConnection({
      host: '$DB_HOST',
      port: $DB_PORT,
      user: '$DB_USER',
      password: '$DB_PASS',
      database: '$DB_NAME',
      connectTimeout: 10000
    });
    
    const [rows] = await connection.execute('SELECT VERSION() as version, NOW() as current_time');
    console.log('✅ Node.js数据库连接成功');
    console.log('数据库版本:', rows[0].version);
    console.log('服务器时间:', rows[0].current_time);
    
    await connection.end();
    process.exit(0);
  } catch (error) {
    console.log('❌ Node.js数据库连接失败:', error.message);
    process.exit(1);
  }
})();
EOF
        
        if timeout 15 node test-db-connection.js 2>/dev/null; then
            log_pass "Node.js数据库连接测试成功"
        else
            log_fail "Node.js数据库连接测试失败"
        fi
        
        # 清理测试文件
        rm -f test-db-connection.js
    else
        log_warn "Node.js不可用或不在项目目录中，跳过Node.js数据库测试"
    fi
}

# 7. SSH连接测试
test_ssh_connection() {
    echo "\n🔐 SSH连接测试"
    echo "----------------------------------------"
    
    log_test "测试SSH连接"
    if timeout 10 ssh -o ConnectTimeout=5 -o BatchMode=yes root@$SERVER_IP "echo 'SSH连接成功'" 2>/dev/null; then
        log_pass "SSH连接正常"
        
        # 获取服务器基本信息
        log_info "服务器基本信息:"
        ssh -o ConnectTimeout=5 root@$SERVER_IP << 'EOF'
echo "操作系统: $(lsb_release -d 2>/dev/null | cut -f2 || uname -s)"
echo "内核版本: $(uname -r)"
echo "运行时间: $(uptime -p 2>/dev/null || uptime)"
echo "磁盘使用: $(df -h / | tail -1 | awk '{print $5}' | sed 's/%//')% 已使用"
echo "内存使用: $(free -m | awk 'NR==2{printf "%.1f%%", $3*100/$2 }' 2>/dev/null || echo '无法获取')"
EOF
    else
        log_fail "SSH连接失败"
        log_info "请检查:"
        echo "  1. SSH密钥是否正确配置"
        echo "  2. 服务器是否正在运行"
        echo "  3. 防火墙是否允许SSH连接"
    fi
}

# 8. 服务器服务状态检查
test_server_services() {
    echo "\n🖥️ 服务器服务状态检查"
    echo "----------------------------------------"
    
    log_test "检查服务器上的关键服务"
    if timeout 10 ssh -o ConnectTimeout=5 root@$SERVER_IP "echo 'SSH连接成功'" 2>/dev/null; then
        log_pass "SSH连接正常，开始检查服务"
        
        ssh -o ConnectTimeout=10 root@$SERVER_IP << 'EOF'
echo "🔍 检查关键服务状态:"

# 检查Nginx
if systemctl is-active --quiet nginx; then
    echo "✅ Nginx: 运行中"
else
    echo "❌ Nginx: 未运行"
fi

# 检查Node.js进程
if pgrep -f "node.*production-server.js\|node.*start-server.js" > /dev/null; then
    echo "✅ Node.js API: 运行中"
    echo "   进程信息: $(pgrep -f 'node.*production-server.js\|node.*start-server.js' | head -1 | xargs ps -p | tail -1)"
else
    echo "❌ Node.js API: 未运行"
fi

# 检查PM2进程
if command -v pm2 &> /dev/null; then
    echo "📊 PM2进程状态:"
    pm2 status 2>/dev/null || echo "   PM2无进程运行"
else
    echo "⚠️ PM2未安装"
fi

# 检查端口监听
echo "🔌 端口监听状态:"
netstat -tlnp 2>/dev/null | grep -E ':(80|443|3000|3306|6379)' | while read line; do
    echo "   $line"
done

# 检查磁盘空间
echo "💾 磁盘使用情况:"
df -h | grep -E '^/dev/' | while read line; do
    echo "   $line"
done

# 检查内存使用
echo "🧠 内存使用情况:"
free -h | head -2 | tail -1 | awk '{print "   使用: "$3" / 总计: "$2" ("$3/$2*100"%)"}'  2>/dev/null || free -h

# 检查最近的错误日志
echo "📝 最近的错误日志 (最后5条):"
journalctl -p err -n 5 --no-pager 2>/dev/null | tail -5 || echo "   无法获取系统错误日志"
EOF
        
        log_pass "服务器服务状态检查完成"
    else
        log_fail "无法连接到服务器，跳过服务状态检查"
    fi
}

# 生成测试报告
generate_report() {
    echo "\n📊 生成测试报告"
    echo "========================================"
    
    # 计算成功率
    if [ $TOTAL_TESTS -gt 0 ]; then
        SUCCESS_RATE=$(( PASSED_TESTS * 100 / TOTAL_TESTS ))
    else
        SUCCESS_RATE=0
    fi
    
    # 确定整体状态
    if [ $SUCCESS_RATE -ge 90 ]; then
        OVERALL_STATUS="🟢 优秀"
    elif [ $SUCCESS_RATE -ge 70 ]; then
        OVERALL_STATUS="🟡 良好"
    elif [ $SUCCESS_RATE -ge 50 ]; then
        OVERALL_STATUS="🟠 需要改进"
    else
        OVERALL_STATUS="🔴 需要紧急修复"
    fi
    
    # 生成报告文件
    cat > connectivity-test-report.md << EOF
# 连通性测试报告

**测试时间**: $(date)  
**测试版本**: v1.0  
**整体状态**: $OVERALL_STATUS

## 📊 测试统计

- **总测试数**: $TOTAL_TESTS
- **通过测试**: $PASSED_TESTS
- **失败测试**: $FAILED_TESTS
- **成功率**: $SUCCESS_RATE%

## 🎯 测试结果摘要

### ✅ 通过的测试
$(grep -E "\[PASS\]" connectivity-test.log 2>/dev/null | sed 's/^/- /' || echo "- 无通过的测试")

### ❌ 失败的测试
$(grep -E "\[FAIL\]" connectivity-test.log 2>/dev/null | sed 's/^/- /' || echo "- 无失败的测试")

### ⚠️ 警告信息
$(grep -E "\[WARN\]" connectivity-test.log 2>/dev/null | sed 's/^/- /' || echo "- 无警告信息")

## 🔧 建议的修复措施

EOF

    # 根据失败的测试添加建议
    if [ $FAILED_TESTS -gt 0 ]; then
        cat >> connectivity-test-report.md << EOF
### 立即修复
1. **运行紧急修复脚本**: \`./emergency-production-fix.sh\`
2. **开放MySQL端口**: 在阿里云安全组中开放3306端口
3. **修复Nginx配置**: 确保API路由正确配置
4. **重启相关服务**: 重启Nginx和Node.js应用

### 验证修复
1. 重新运行此测试脚本: \`./connectivity-test.sh\`
2. 手动测试关键端点
3. 检查应用日志

EOF
    else
        cat >> connectivity-test-report.md << EOF
### 维护建议
1. **定期监控**: 建议每日运行此测试脚本
2. **性能优化**: 考虑优化数据库查询和API响应时间
3. **安全加固**: 定期更新SSL证书和系统补丁

EOF
    fi
    
    cat >> connectivity-test-report.md << EOF
## 📞 技术支持

如需技术支持，请提供以下信息：
- 此测试报告
- 服务器日志: \`journalctl -f\`
- 应用日志: \`/opt/cumbull/backend/logs/\`

---
**报告生成时间**: $(date)  
**下次建议测试**: $(date -d '+1 day' 2>/dev/null || date -v+1d 2>/dev/null || echo '24小时后')
EOF
    
    echo "\n📋 测试总结"
    echo "----------------------------------------"
    echo "总测试数: $TOTAL_TESTS"
    echo "通过: $PASSED_TESTS"
    echo "失败: $FAILED_TESTS"
    echo "成功率: $SUCCESS_RATE%"
    echo "整体状态: $OVERALL_STATUS"
    echo ""
    echo "📄 详细报告已保存到: connectivity-test-report.md"
    
    if [ $FAILED_TESTS -gt 0 ]; then
        echo ""
        echo "🚨 发现问题，建议立即执行修复:"
        echo "   ./emergency-production-fix.sh"
    fi
}

# 主执行流程
main() {
    # 重定向输出到日志文件
    exec > >(tee connectivity-test.log)
    exec 2>&1
    
    echo "🔍 开始全面连通性测试"
    echo "测试目标: $SERVER_IP ($API_DOMAIN)"
    echo "========================================"
    
    test_dns_resolution
    test_port_connectivity
    test_ssl_certificates
    test_http_responses
    test_api_health
    test_database_connection
    test_ssh_connection
    test_server_services
    
    generate_report
    
    echo "\n🎉 连通性测试完成！"
    echo "========================================"
}

# 执行主流程
main "$@"